package com.huawei.bitfun.insight;

import com.huawei.bitfun.insight.utils.Common;
import com.huawei.bitfun.insight.utils.InsightExClassPathUtil;
import com.huawei.deveco.insight.ohos.resourcehandler.controller.HandlerMethod;
import com.huawei.deveco.insight.ohos.resourcehandler.controller.MappingRegistration;
import com.huawei.deveco.insight.ohos.resourcehandler.controller.MappingRegistry;
import com.huawei.deveco.insight.ohos.resourcehandler.controller.MappingRegistryManager;
import com.huawei.deveco.insight.ohos.resourcehandler.controller.RequestMapping;
import com.intellij.openapi.util.text.Strings;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public class InsightExMappingRegistryManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(InsightExMappingRegistryManager.class);

    private static volatile InsightExMappingRegistryManager instance;

    private final MappingRegistry mappingRegistry = new MappingRegistry();

    private boolean isLoaded;

    public static InsightExMappingRegistryManager getInstance() {
        if (instance == null) {
            synchronized (InsightExMappingRegistryManager.class) {
                if (instance == null) {
                    instance = new InsightExMappingRegistryManager();
                }
            }
        }
        return instance;
    }

    public synchronized void loadRequestMapping() {
        if (isLoaded) {
            return;
        }
        List<Class<?>> classList = InsightExClassPathUtil.findClassWithAnyAnnotation(
                Collections.singleton(RequestMapping.class));
        classList.forEach(this::loadRequestMappingForClass);
        MappingRegistryManager.getInstance().loadRequestMapping();
        isLoaded = true;
    }

    private void loadRequestMappingForClass(Class<?> aClass) {
        RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class);
        String parentPath = requestMapping.path();
        if (StringUtils.isEmpty(parentPath)) {
            LOGGER.warn("Class path is empty. Class: {}", aClass);
            return;
        }
        for (Method method : aClass.getMethods()) {
            RequestMapping requestMappingMethod = method.getAnnotation(RequestMapping.class);
            if (requestMappingMethod == null) {
                continue;
            }
            if (StringUtils.isEmpty(requestMapping.path())) {
                LOGGER.warn("Class path is empty. Class: {}, method: {}.", aClass, method.getName());
                continue;
            }
            String completePath = Common.joinWithForwardSlash(parentPath, requestMappingMethod.path());
            if (mappingRegistry.containsMapping(completePath)) {
                LOGGER.warn("Duplicate request mapping for: {}", completePath);
                continue;
            }
            MappingRegistration mappingRegistration = new MappingRegistration(
                    new HandlerMethod(aClass, method), List.of(parentPath, requestMappingMethod.path()));
            mappingRegistry.registerMapping(completePath, mappingRegistration);
        }
    }

    public Optional<HandlerMethod> getHandlerMethod(List<String> pathList) {
        String completePath = Strings.join(pathList, "/");
        if (mappingRegistry.getHandlerMethod(completePath).isPresent()) {
            return mappingRegistry.getHandlerMethod(completePath);
        }
        return MappingRegistryManager.getInstance().getHandlerMethod(pathList);
    }
}
